package my.menu;

import my.vo.voImpl.User;

import java.lang.reflect.Method;
import java.util.*;

/**
 * @author 星环
 * @date 2022/10/31 13:41:43
 * @description 菜单
 */
public abstract class Menu {
    protected MenuView view = new MenuView() {
    };

    //用于它子类的输入
    protected Scanner sc = new Scanner(System.in);

    //用于按顺序存放选项方法的反射和描述
    private final ArrayList<Item> items = new ArrayList<>();

    protected User user;

    //没有选项没什么意义
    private Menu(){

    }

    /**
     * 只允许子类调用
     * @param nameList 子类选项的名字列表
     * @param funcNameList 子类选项对应方法的名字列表
     */
    protected Menu(List<String> nameList, List<String> funcNameList){
        //使用所给的数据初始化，因为子类运行时返回它定义的方法，可以从中找到对应的
        init(nameList,funcNameList, List.of(getClass().getDeclaredMethods()));
    }

    /**
     * 用给的数据完成方法引用列表
     * @param descNameList 选项名称列表
     * @param funcNameList 选项对应方法名称列表
     * @param methodList 子类定义的所有方法
     */
    protected void init(List<String> descNameList, List<String> funcNameList, List<Method> methodList){
        //nameList和funcNameList是对应的，向Map methodMap中加入 name-method，将methodList根据getName添加为tMap<getName,method>
        //并根据tMap.get(funcName) ->  items.add(nameList.get(i),tMap.get(funcNameList.get(i)));
        //输出时直接遍历items就行
        Map<String, Method> tMap = new HashMap<>();
//        将methodList根据getName做成tMap<getName,method>，方便一会查
        for (Method method : methodList) {
            tMap.put(method.getName(),method);
        }
        for (int i = 0; i < funcNameList.size(); i++) {
            items.add(new Item(descNameList.get(i), tMap.get(funcNameList.get(i))));
        }
        System.out.println("[debug]-选项列表：");
        for (int i = 0;i < funcNameList.size();i++){
            System.out.println(items.get(i).desc + items.get(i).method.getName());
        }
    }

    /**
     * 声明为抽象好像没什么用，子类也用不到这重写，但是可以父类调用 runFunc ---{before sub.override after}实现切面？难道真是这样，有意思
     */
    protected abstract class MenuView{

        public void showTip(String tip){
            System.out.println(tip);
        }

        /**
         * 显示子类的菜单，根据反射来的方法调用它们的方法
         */
        protected  void showMenu(){
            for (int i = 0; i < items.size(); i++) {
                System.out.print(i+1 + "." + items.get(i).desc + "\t");
                if(i % 2 == 1 ){
                    System.out.println();
                }
            }
            System.out.println("0.返回上一级/退出");
        }
        protected void choiceErrorTip(){
            System.out.println("选择错误");
        }
    }

    protected static class Item{
        public Item(String desc, Method method) {
            this.desc = desc;
            this.method = method;
        }
        String desc;
        Method method;

    }



    public void entrance() {
        boolean needContinue = true;
        while (needContinue){
            view.showMenu();
            int option = sc.nextInt();
            if(option == 0){
                return;
            }
            if(option > items.size() || option < 0){
                view.choiceErrorTip();
                continue;
            }
            Method method = items.get(option-1).method;
            method.setAccessible(true);
            try {
                System.out.println("[调用选项-" + items.get(option-1).desc + "]");//这就是切面吗？
                needContinue = (Boolean) method.invoke(this);
                System.out.println("[调用选项-" + items.get(option-1).desc + "结束]");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }


    }

    protected User getUser() {
        return user;
    }

    protected void setUser(User user) {
        this.user = user;
    }
}
